package com.reebake.ideal.security.authentication;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.reebake.ideal.security.core.AuthenticationFactor;
import com.reebake.ideal.security.core.LoginFailureEvent;
import com.reebake.ideal.servlet.core.ResponseBodyWrapper;
import com.reebake.ideal.servlet.util.WebUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

import java.io.IOException;

@AllArgsConstructor
public class LoginAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
	private final ApplicationEventPublisher applicationEventPublisher;
	private final ObjectMapper objectMapper;

	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {
		if(WebUtil.isAjaxRequest(request)) {
			String requestBody = IoUtil.read(request.getInputStream(), CharsetUtil.CHARSET_UTF_8);
			if(JSONUtil.isTypeJSONArray(requestBody)) {
				JsonNode root = objectMapper.readTree(requestBody);
				for(JsonNode node : root) {
					String username = node.get(LambdaUtil.getFieldName(AuthenticationFactor::getUsername)).asText("");
					if(StrUtil.isBlank(username)) {
						continue;
					}
					LoginFailureEvent loginFailureEvent = new LoginFailureEvent(this, username, null);
					applicationEventPublisher.publishEvent(loginFailureEvent);
				}
			}

			response.setStatus(HttpStatus.OK.value());
			ResponseBodyWrapper.wrapResponse(response, HttpStatus.UNAUTHORIZED.value(), exception);
		}else {
			super.onAuthenticationFailure(request, response, exception);
		}
	}
}
